package ru.payment.wm.impl;

import org.dom4j.Document;
import org.dom4j.Element;
import ru.payment.wm.*;

import java.util.List;

/**
 *
 * User: sergey
 * Date: 22.04.2009
 * Time: 14:07:36
 *
 */
public class DefaultResponseBuilder implements WebMoneyResponseBuilder {

  private WebMoneyObjectFactory objectFactory = new DefaultWMObjectFactory();
  private X2OHelper x2oHelper = new X2OHelper();

  private InvoiceParser invoiceParser = new InvoiceParser();
  private OperationParser operationParser = new OperationParser();
  private MessageParser messageParser = new MessageParser();
  private PurseParser purseParser = new PurseParser();
  private DirectoryParser directoryParser = new DirectoryParser();
  private AttestatRowParser attestatRowParser = new AttestatRowParser();
  private WMIDRowParser wmidRowParser = new WMIDRowParser();
  private UserInfoRowParser userInfoRowParser = new UserInfoRowParser();
  private TrustParser trustParser = new TrustParser();

  public WebMoneyObjectFactory getObjectFactory() {
    return objectFactory;
  }

  public void setObjectFactory(WebMoneyObjectFactory objectFactory) {
    this.objectFactory = objectFactory;
  }

  public X1Response buildX1Response(Document doc) throws WebMoneyException {
    X1Response r = objectFactory.createX1Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("invoice");
    if (e != null) {
      Invoice invoice = objectFactory.createInvoice();
      invoiceParser.parse(e, invoice);
      r.setInvoice(invoice);
    }
    
    return r;
  }

  public X2Response buildX2Response(Document doc) throws WebMoneyException {
    X2Response r = objectFactory.createX2Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("operation");
    if (e != null) {
      Operation op = objectFactory.createOperation();
      operationParser.parse(e, op);
      r.setOperation(op);
    }

    return r;
  }

  public X3Response buildX3Response(Document doc) throws WebMoneyException {
    X3Response r = objectFactory.createX3Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("operations");
    if (e != null) {
      List<Element> eOps = e.elements("operation");
      for (Element eOp : eOps) {
        Operation op = objectFactory.createOperation();
        operationParser.parse(eOp, op);
        r.getOperationList().add(op);
      }
    }

    return r;
  }

  public X4Response buildX4Response(Document doc) throws WebMoneyException {
    X4Response r = objectFactory.createX4Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("outinvoices");
    if (e != null) {
      List<Element> eInvs = e.elements("outinvoice");
      for (Element eInv : eInvs) {
        Invoice inv = objectFactory.createInvoice();
        invoiceParser.parse(eInv, inv);
        r.getInvoiceList().add(inv);
      }
    }

    return r;
  }

  public X5Response buildX5Response(Document doc) throws WebMoneyException {
    X5Response r = objectFactory.createX5Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("operation");
    if (e != null) {
      Operation op = objectFactory.createOperation();
      operationParser.parse(e, op);
      r.setOperation(op);
    }

    return r;
  }

  public X6Response buildX6Response(Document doc) throws WebMoneyException {
    X6Response r = objectFactory.createX6Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("message");
    if (e != null) {
      Message msg = objectFactory.createMessage();
      messageParser.parse(e, msg);
      r.setMessage(msg);
    }

    return r;
  }

  public X7Response buildX7Response(Document doc) throws WebMoneyException {
    X7Response r = objectFactory.createX7Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("testsign");
    if (e != null) {
      String szRes = e.element("res").getText();
      r.setAuthenticated("yes".equals(szRes));
    }

    return r;
  }

  public X8Response buildX8Response(Document doc) throws WebMoneyException {
    X8Response r = objectFactory.createX8Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("testwmpurse");
    if (e != null) {
      r.setFoundWmId(e.element("wmid").getText());
      r.setFoundPurse(e.element("purse").getText());
    }

    return r;
  }

  public X9Response buildX9Response(Document doc) throws WebMoneyException {
    X9Response r = objectFactory.createX9Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("purses");

    if (e != null) {
      List<Element> ePurses = e.elements("purse");
      for (Element eP : ePurses) {
        Purse p = objectFactory.createPurse();
        purseParser.parse(eP, p);
        r.getPurseList().add(p);
      }
    }

    return r;
  }

  public X10Response buildX10Response(Document doc) throws WebMoneyException {
    X10Response r = objectFactory.createX10Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("ininvoices");

    if (e != null) {
      List<Element> eInvs = e.elements("ininvoice");
      for (Element eInv : eInvs) {
        Invoice inv = objectFactory.createInvoice();
        invoiceParser.parse(eInv, inv);
        r.getInvoiceList().add(inv);
      }
    }

    return r;
  }

  public X11Response buildX11Response(Document doc) throws WebMoneyException {
    X11Response r = objectFactory.createX11Response();
    parseResponseHeaderFromAttr(r, doc);

    Element e = doc.getRootElement().element("fullaccess");
    r.setFullAccess(x2oHelper.asBoolean(e, false));

    Element eCert = doc.getRootElement().element("certinfo");
    if (eCert!=null) {
      CertificateInfo certInfo = objectFactory.createCertificateInfo();
      certInfo.setWmId(x2oHelper.attrAsString(eCert.attribute("wmid"), ""));

      Element eDir = eCert.element("directory");
      if (eDir != null) {
        Directory dir = objectFactory.createDirectory();
        directoryParser.parse(eDir, dir);
        certInfo.setDirectory(dir);
      }

      Element eAtt = eCert.element("attestat");
      List<Element> eAttRows = eAtt.elements("row");
      for (Element eAttRow : eAttRows) {
        AttestatRow row = objectFactory.createAttestatRow();
        attestatRowParser.parse(eAttRow, row);
        certInfo.getAttestatList().add(row);
      }

      Element eWmIds = eCert.element("wmids");
      List<Element> eIdRows = eWmIds.elements("row");
      for (Element eIdRow : eIdRows) {
        WMIDRow row = objectFactory.createWMIDRow();
        wmidRowParser.parse(eIdRow, row);
        certInfo.getWmIdList().add(row);
      }

      Element eUsrInfoValue = eCert.element("userinfo").element("value");
      List<Element> eValueRows = eUsrInfoValue.elements("row");
      for (Element eValueRow : eValueRows) {
        UserInfoRow row = objectFactory.createUserInfoRow();
        userInfoRowParser.parse(eValueRow, row);
        certInfo.getUserInfoValueList().add(row);
      }

      Element eUsrInfoCheckLock = eCert.element("userinfo").element("check-lock");
      List<Element> eCheckLockRows = eUsrInfoCheckLock.elements("row");
      for (Element eCheckLockRow : eCheckLockRows) {
        UserInfoRow row = objectFactory.createUserInfoRow();
        userInfoRowParser.parse(eCheckLockRow, row);
        certInfo.getUserInfoCheckLockList().add(row);        
      }

      r.setCertificateInfo(certInfo);
    }

    return r;
  }

  public X13Response buildX13Response(Document doc) throws WebMoneyException {
    X13Response r = objectFactory.createX13Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("operation");
    if (e != null) {
      Operation op = objectFactory.createOperation();
      operationParser.parse(e, op);
      r.setOperation(op);
    }

    return r;
  }

  public X14Response buildX14Response(Document doc) throws WebMoneyException {
    X14Response r = objectFactory.createX14Response();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("operation");
    if (e != null) {
      Operation op = objectFactory.createOperation();
      operationParser.parse(e, op);
      r.setOperation(op);
    }

    return r;
  }

  public X15ListResponse buildX15Response(Document doc) throws WebMoneyException {
    X15ListResponse r = objectFactory.createX15ListResponse();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("trustlist");
    if (e != null) {
      List<Element> eTrusts = e.elements("trust");
      for (Element eTrust : eTrusts) {
        Trust t = objectFactory.createTrust();
        trustParser.parse(eTrust, t);
        r.getTrustList().add(t);
      }
    }

    return r;
  }

  public X15SaveResponse buildX15SaveResponse(Document doc) throws WebMoneyException {
    X15SaveResponse r = objectFactory.createX15SaveResponse();
    parseResponseHeader(r, doc);

    Element e = doc.getRootElement().element("trust");
    if (e != null) {
      Trust t = objectFactory.createTrust();
      trustParser.parse(e, t);
      r.setTrust(t);
    }
    return r;
  }

  private void parseResponseHeader(WebMoneyResponse wmr, Document doc) {
    wmr.setRequestNumber(x2oHelper.asLong(doc.getRootElement().element("reqn"), 0));
    wmr.setReturnCode(x2oHelper.asInt(doc.getRootElement().element("retval"), -999));
    wmr.setReturnCodeDescription(x2oHelper.asString(doc.getRootElement().element("retdesc"), ""));
  }

  private void parseResponseHeaderFromAttr(WebMoneyResponse wmr, Document doc) {
    String szRetVal = doc.getRootElement().attributeValue("retval");
    String szRetDesc = doc.getRootElement().attributeValue("retdesc");
    wmr.setReturnCode(szRetVal!=null&&szRetVal.length()>0?Integer.parseInt(szRetVal):-1);
    wmr.setReturnCodeDescription(szRetDesc!=null&&szRetDesc.length()>0?szRetDesc:"");
  }

}
